package cn.jy.boot.security;

import cn.jy.boot.security.filter.LoginFilter;
import cn.jy.boot.service.MyUserDetailsService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //自定义基于内存的数据源
//    @Override
//    public UserDetailsService userDetailsService(){
//        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
//        userDetailsManager.createUser(User.withUsername("root").password("{noop}123").roles("super").build());
//        return  userDetailsManager;
//    }

    @Autowired
    private DataSource dataSource;

    private final MyUserDetailsService myUserDetailsService;

    @Autowired
    public SecurityConfig(MyUserDetailsService myUserDetailsService) {
        this.myUserDetailsService = myUserDetailsService;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService);
    }

    //暴露
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    //注入自定义的过滤器
    public LoginFilter loginFilter() throws Exception {
        LoginFilter loginFilter = new LoginFilter();
        //指定认证的地址
        loginFilter.setFilterProcessesUrl("/doLogin");
        loginFilter.setUsernameParameter("uname");
        loginFilter.setPasswordParameter("pwd");
        //认证成功后
        loginFilter.setAuthenticationSuccessHandler((request,response,authentication)->{
            //自定义成功之后返回的信息
            Map<String,Object> returnInfo = new HashMap<>();
            returnInfo.put("msg","登陆成功");
            returnInfo.put("code",HttpStatus.OK.value());
//            returnInfo.put("code","200");
            returnInfo.put("authentication",authentication.getPrincipal());
//        把要返回的信息转化为json字符串
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(returnInfo);
//        把json字符串返回
            response.setContentType("text/json;charset=utf-8");
            response.setStatus(HttpStatus.OK.value());
            response.getWriter().print(json);
        });
        //认证失败后
        loginFilter.setAuthenticationFailureHandler((request,response,ex)->{

            //        自定义认证失败信息
            Map<String,Object> info = new HashMap<>();
            info.put("msg","认证失败");
//            info.put("code","500");
            info.put("exception",ex.getMessage());
//        将认证失败信息转化为json
            String json = new ObjectMapper().writeValueAsString(info);
//        将json响应
            response.setContentType("text/json;charset=utf-8");
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            response.getWriter().print(json);
        });
        //指定认证管理器
        loginFilter.setAuthenticationManager(authenticationManagerBean());
        //设置自定义的记住我   向客户端写入cookies
        loginFilter.setRememberMeServices(rememberMeServices());
        return loginFilter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .mvcMatchers("/doLogin").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
//                .loginProcessingUrl("/doLogin")
                .and()
                .rememberMe()//开启记住我  当请求中含有remember-me的 cookie时 启动自动登录
//                .alwaysRemember(true) //总是记住我
                .rememberMeServices(rememberMeServices())
                .and()
                .logout()
                .and()
                .exceptionHandling()//认证异常
                .authenticationEntryPoint((request,response,ex)->{
                    response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    response.getWriter().print("请认证之后再进行操作");
                })
                .and()
                .csrf().disable();
        /*
        * at: 在过滤器链中，使用一个过滤器替代 过滤器链中的一个过滤器
        * before：在过滤器链中 某个过滤器前添加一个过滤器
        * after ：在过滤器链中 某个过滤器后添加一个过滤器
        * */
        http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);

    }

    @Bean
    public RememberMeServices rememberMeServices(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        return new MyPersistentTokenBasedRememberMeServices(UUID.randomUUID().toString(),myUserDetailsService,jdbcTokenRepository);
    }
}
